﻿
/***************************************************************************

Copyright (c) BizRulX. All rights reserved.

***************************************************************************/

using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.Win32;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Text;
using EnvDTE90;
using EnvDTE;
using EnvDTE80;
using System.Reflection;
using VSLangProj;

namespace RuleXSoft.BizRuleCreator
{
    /// <summary>
    /// This is the class that implements the package exposed by this assembly.
    ///
    /// The minimum requirement for a class to be considered a valid package for Visual Studio
    /// is to implement the IVsPackage interface and register itself with the shell.
    /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
    /// to do it: it derives from the Package class that provides the implementation of the 
    /// IVsPackage interface and uses the registration attributes defined in the framework to 
    /// register itself and its components with the shell.
    /// </summary>
    // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
    // a package.
    [DefaultRegistryRoot(@"Software\Microsoft\VisualStudio\10.0")]
    [PackageRegistration(UseManagedResourcesOnly = true)]
    [ProvideEditorLogicalView(typeof(EditorFactory), "{7651a703-06e5-11d1-8ebd-00a0c90f26ea}")]
    [InstalledProductRegistration(false, "#100", "#102", "1.0", IconResourceID = 400)]
    [ProvideLoadKey("Standard", "1.0", "BizRulX-View Editor", "Microsoft Company", 1)]

    [XmlDesignerView(typeof(EditorFactory), "{7651a702-06e5-11d1-8ebd-00a0c90f26ea}",
              Name = "BizRulX-View Editor",
              XmlNamespace = "http://schemas.microsoft.com/AutomationExtensibility",
              Extension = "rulx",
              MatchBoth = false)]

    // We register that our editor supports LOGVIEWID_Designer logical view
    [ProvideEditorLogicalView(typeof(EditorFactory), "{7651a702-06e5-11d1-8ebd-00a0c90f26ea}")]

    ///////////////
    [ProvideEditorExtension(typeof(EditorFactory), ".rulx", 50,
              ProjectGuid = "{A2FE74E1-B743-11d0-AE1A-00A0C90FFFC3}",
              TemplateDir = "Templates",
              NameResourceID = 105,
              DefaultName = "BizRuleXVS2010")]
    [ProvideKeyBindingTable(GuidList.guidBizRuleXVS2010EditorFactoryString, 102)]
    /////////////

    //// We register our AddNewItem Templates for all of the projects we want to be available for:
    //// Miscellaneous Files Project
    //[ProvideEditorExtension(typeof(EditorFactory), ".rulx", 32,
    //          ProjectGuid = "{A2FE74E1-B743-11d0-AE1A-00A0C90FFFC3}",
    //          TemplateDir = "..\\..\\Templates",
    //          NameResourceID = 106)]
    //// Solution Folders Project
    //[ProvideEditorExtension(typeof(EditorFactory), ".rulx", 32,
    //          ProjectGuid = "{2150E333-8FDC-42a3-9474-1A3956D46DE8}",
    //          TemplateDir = "..\\..\\Templates",
    //          NameResourceID = 106)]
    //// Microsoft Visual Basic Project
    //[ProvideEditorExtension(typeof(EditorFactory), ".rulx", 32,
    //          ProjectGuid = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}",
    //          TemplateDir = "..\\..\\Templates",
    //          NameResourceID = 106)]
    //// Microsoft Visual C# Project
    //[ProvideEditorExtension(typeof(EditorFactory), ".rulx", 32,
    //        ProjectGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}",
    //         TemplateDir = "..\\..\\Templates",
    //          NameResourceID = 106)]
    //// Microsoft Visual J# Project
    //[ProvideEditorExtension(typeof(EditorFactory), ".rulx", 32,
    //       ProjectGuid = "{E6FDF86B-F3D1-11D4-8576-0002A516ECE8}",
    //         TemplateDir = "..\\..\\Templates",
    //          NameResourceID = 106)]
    //// We register the XML Editor ("{FA3CD31E-987B-443A-9B81-186104E8DAC1}") as an EditorFactoryNotify
    //// object to handle our ".addin" file extension for the following projects:
    //// Microsoft Visual Basic Project
    //[EditorFactoryNotifyForProjectAttribute("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}", ".rulx", "{FA3CD31E-987B-443A-9B81-186104E8DAC1}")]
    //// Microsoft Visual C# Project
    //[EditorFactoryNotifyForProjectAttribute("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", ".rulx", "{FA3CD31E-987B-443A-9B81-186104E8DAC1}")]
    //// Microsoft Visual J# Project
    //[EditorFactoryNotifyForProjectAttribute("{E6FDF86B-F3D1-11D4-8576-0002A516ECE8}", ".rulx", "{FA3CD31E-987B-443A-9B81-186104E8DAC1}")]
    [Guid(GuidList.guidBizRuleXVS2010PkgString)]
    // This attribute is needed to let the shell know that this package exposes some menus.
    [ProvideMenuResource("Menus.ctmenu", 1)]
    public sealed class BizRuleXVS2010Package : Package
    {
        public delegate void ProcessHierarchyNode(IVsHierarchy hierarchy, uint itemid, int recursionLevel);
        
        public ProcessHierarchyNode _processNode = new ProcessHierarchyNode(DisplayHierarchyNode);

        public string SelectedProjectType { get; set; }

        private SelectionEvents mySelectionEvents;
        private uint mySelectionEventsCookie;
        
        /// <summary>
        /// Default constructor of the package.
        /// Inside this method you can place any initialization code that does not require 
        /// any Visual Studio service because at this point the package object is created but 
        /// not sited yet inside Visual Studio environment. The place to do all the other 
        /// initialization is the Initialize method.
        /// </summary>
        public BizRuleXVS2010Package()
        {
            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
        }



        /////////////////////////////////////////////////////////////////////////////
        // Overriden Package Implementation
        #region Package Members

        /// <summary>
        /// Initialization of the package; this method is called right after the package is sited, so this is the place
        /// where you can put all the initilaization code that rely on services provided by VisualStudio.
        /// </summary>
        protected override void Initialize()
        {
            
            
            Trace.WriteLine (string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));
            base.Initialize();

            

            

            //_applicationObject = (DTE2)application;
            //_addInInstance = (AddIn)addInInst;

            //Create Editor Factory. Note that the base Package class will call Dispose on it.
            base.RegisterEditorFactory(new EditorFactory(this));

            //////////////////////////////////////
            int iAdviseSelectionEventsOK = VSConstants.S_OK;
            mySelectionEvents = new SelectionEvents();

            IVsMonitorSelection selectionService = (IVsMonitorSelection)this.GetService(typeof(SVsShellMonitorSelection));

            iAdviseSelectionEventsOK = selectionService.AdviseSelectionEvents(mySelectionEvents, out mySelectionEventsCookie);

            /////////////////////////////////////

            // Add our command handlers for menu (commands must exist in the .vsct file)
            OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
            if ( null != mcs )
            {
                // Create the command for the menu item.
                CommandID menuCommandID = new CommandID(GuidList.guidBizRuleXVS2010CmdSet, (int)PkgCmdIDList.cmdidMyCommand);
                MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID );
                mcs.AddCommand( menuItem );

                // Create the command for the RuleX menu item.
                CommandID menuRuleXCommandID = new CommandID(GuidList.guidBizRuleXVS2010CmdSet, (int)PkgCmdIDList.cmdidProjContextMenu);
                MenuCommand menuRuleXItem = new MenuCommand(ShowRuleXWindow, menuRuleXCommandID);
                mcs.AddCommand(menuRuleXItem);

                if (iAdviseSelectionEventsOK == VSConstants.S_OK)
                {
                    // Create the command for the RuleX menu item.
                    CommandID menuRuleXUpdateCommandID = new CommandID(GuidList.guidBizRuleXVS2010CmdSet, (int)PkgCmdIDList.cmdidMyUpdateRulXCommand);
                    MenuCommand menuRuleXUpdateItem = new MenuCommand(ShowRuleXWindowForUpdate, menuRuleXUpdateCommandID);
                    mcs.AddCommand(menuRuleXUpdateItem); 
                }
            }

            
        }
        #endregion

        protected override void Dispose(bool disposing)
        {

            IVsMonitorSelection selectionService = (IVsMonitorSelection)this.GetService(typeof(SVsShellMonitorSelection));
            if (selectionService != null)
            {
                selectionService.UnadviseSelectionEvents(mySelectionEventsCookie);
            }

            base.Dispose(disposing);
        }



        /// <summary>
        /// This function is called when the user clicks the menu item that shows the 
        /// tool window. See the Initialize method to see how the menu item is associated to 
        /// this function using the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void ShowRuleXWindow(object sender, EventArgs e)
        {
            // Get the instance number 0 of this tool window. This window is single instance so this instance
            // is actually the only one.
            // The last flag is set to true so that if the tool window does not exists it will be created.
            //ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
            //if ((null == window) || (null == window.Frame))
            //{
            //    throw new NotSupportedException(Resources.CanNotCreateWindow);
            //}
            //IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
            //Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());

            BizRuleCreator.BizRuleGenerater frmRuleXGen = new BizRuleCreator.BizRuleGenerater();
            frmRuleXGen.OnRuleXGenerated += new EventHandler(frmRuleXGen_OnRuleXGenerated);

            List<string> objExistingRulXFileList = new List<string>();
            objExistingRulXFileList = GetExistingRulXFileList();

            frmRuleXGen.ExistingRulXFileList = objExistingRulXFileList;
            frmRuleXGen.SelectedProjectType = this.SelectedProjectType;
            frmRuleXGen.DialogOpeningMode = 0; // rulX New mode

            frmRuleXGen.ShowDialog();

            //System.Windows.Forms.MessageBox.Show("Calling sequence...");

            
        }

        /// <summary>
        /// This function is called when the user clicks the menu item that shows the 
        /// tool window. See the Initialize method to see how the menu item is associated to 
        /// this function using the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void ShowRuleXWindowForUpdate(object sender, EventArgs e)
        {
            BizRuleCreator.BizRuleGenerater frmRuleXGen = new BizRuleCreator.BizRuleGenerater();
            //frmRuleXGen.OnRuleXUpdated += new EventHandler(frmRuleXGen_OnRuleXUpdated);

            frmRuleXGen.OnRuleXUpdated += new BizRuleGenerater.RulXEventHandler(frmRuleXGen_OnRuleXUpdated);

            List<string> objExistingRulXFileList = new List<string>();
            objExistingRulXFileList = GetExistingRulXFileList();

            frmRuleXGen.ExistingRulXFileList = objExistingRulXFileList;
            frmRuleXGen.SelectedProjectType = this.SelectedProjectType;
            frmRuleXGen.DialogOpeningMode = 1; // rulX update mode

            //var dte = (DTE2)GetService(typeof(SDTE));
            //var doc = dte.ActiveDocument;

            SelectedItem SelItemObj;
            SelectedItems SelItems;
            EnvDTE.Project project = VSEnvUtility.GetSelectedProjectHierarchyInstance();


            SelItemObj = VSEnvUtility.GetSelectedItem(project.DTE);
            //string strRulXPath1 = VSEnvUtility.GetPathFull(project.DTE, SelItemObj.Name);

            string strRulXPath = SelItemObj.ProjectItem.Properties.Item("FullPath").Value.ToString();

            frmRuleXGen.RulXFileNameForUpdate = strRulXPath;
                

            frmRuleXGen.ShowDialog();

            //System.Windows.Forms.MessageBox.Show("Update Calling sequence...");


        }

        void frmRuleXGen_OnRuleXUpdated(object sender, RulXEventArgs e)
        {
            ExecuteRuleXActionForUpdate(e.RulXFileName); // Updating existing RulX File
        }

        void frmRuleXGen_OnRuleXGenerated(object sender, EventArgs e)
        {
            ExecuteRuleXAction(); // New RulX File crration
        }

        private void GenerateRuleXProjectItem()
        {
            //Get the solution service so we can traverse each project hierarchy contained within.
            IVsSolution solution = (IVsSolution)GetService(typeof(SVsSolution));
            if (null != solution)
            {
                IVsHierarchy solutionHierarchy = solution as IVsHierarchy;
                if (null != solutionHierarchy)
                {
                    
                }
            }
        }

        /// <summary>
        /// This function is the callback used to execute a command when the a menu item is clicked.
        /// See the Initialize method to see how the menu item is associated to this function using
        /// the OleMenuCommandService service and the MenuCommand class.
        /// </summary>
        private void MenuItemCallback(object sender, EventArgs e)
        {
            // Show a Message Box to prove we were here
            IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
            Guid clsid = Guid.Empty;
            int result;
            Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(
                       0,
                       ref clsid,
                       "BizRuleXVS2010",
                       string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.ToString()),
                       string.Empty,
                       0,
                       OLEMSGBUTTON.OLEMSGBUTTON_OK,
                       OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
                       OLEMSGICON.OLEMSGICON_INFO,
                       0,        // false
                       out result));
        }

        #region Biz RuleX section
        private const string tempOutputDir = @"C:\Windows\Temp\BizRuleGen";
        private const string xsdFileName = @"XmlRuleSetSchema.xsd";

        public string SolutionFullName { get; set; }
        public Solution3 SolutionContext { get; set; }

        public string OutputAttributeFileName { get; set; }

        /// <summary>
        /// Enumerate only visible hierarchy project items recursively traversing nested hierarchies.
        /// This will enumerate the same set of items that are displayed in the Solution Explorer.
        /// Projects that support the notion of "Show All Files" can change which items are visible.
        /// </summary>
        private void TraverseVisibleItemsCommand(object caller, EventArgs args)
        {
            //Get the solution service so we can traverse each project hierarchy contained within.
            IVsSolution solution = (IVsSolution)GetService(typeof(SVsSolution));
            if (null != solution)
            {
                IVsHierarchy solutionHierarchy = solution as IVsHierarchy;
                if (null != solutionHierarchy)
                {
                    OutputCommandString("\n\nTraverse Visible Items Recursively:\n");
                    this.EnumHierarchyItems(solutionHierarchy, VSConstants.VSITEMID_ROOT, 0, true, true, _processNode);
                }
            }
        }

        /// <summary>
        /// This function diplays the name of the Hierarchy node. This function is passed to the 
        /// Hierarchy enumeration routines to process the current node.
        /// </summary>
        /// <param name="hierarchy">Hierarchy of the current node</param>
        /// <param name="itemid">Itemid of the current node</param>
        /// <param name="recursionLevel">Depth of recursion in hierarchy enumeration. We add one tab
        /// for each level in the recursion.</param>
        private static void DisplayHierarchyNode(IVsHierarchy hierarchy, uint itemid, int recursionLevel)
        {
            object pVar;
            int hr;

            string text = "";

            for (int i = 0; i < recursionLevel; i++)
                text += "\t";

            //Get the name of the root node in question here and dump its value
            hr = hierarchy.GetProperty(itemid, (int)__VSHPROPID.VSHPROPID_Name, out pVar);
            text += (string)pVar;
            OutputCommandString(text);
        }


        /// <summary>
        /// Enumerates over the hierarchy items for the given hierarchy traversing into nested hierarchies.
        /// </summary>
        /// <param name="hierarchy">hierarchy to enmerate over.</param>
        /// <param name="itemid">item id of the hierarchy</param>
        /// <param name="recursionLevel">Depth of recursion. e.g. if recursion started with the Solution
        /// node, then : Level 0 -- Solution node, Level 1 -- children of Solution, etc.</param>
        /// <param name="hierIsSolution">true if hierarchy is Solution Node. This is needed to special
        /// case the children of the solution to work around a bug with VSHPROPID_FirstChild and 
        /// VSHPROPID_NextSibling implementation of the Solution.</param>
        /// <param name="visibleNodesOnly">true if only nodes visible in the Solution Explorer should
        /// be traversed. false if all project items should be traversed.</param>
        /// <param name="processNodeFunc">pointer to function that should be processed on each
        /// node as it is visited in the depth first enumeration.</param>
        private void EnumHierarchyItems(IVsHierarchy hierarchy, uint itemid, int recursionLevel, bool hierIsSolution, bool visibleNodesOnly, ProcessHierarchyNode processNodeFunc)
        {
            int hr;
            IntPtr nestedHierarchyObj;
            uint nestedItemId;
            Guid hierGuid = typeof(IVsHierarchy).GUID;

            // Check first if this node has a nested hierarchy. If so, then there really are two 
            // identities for this node: 1. hierarchy/itemid 2. nestedHierarchy/nestedItemId.
            // We will recurse and call EnumHierarchyItems which will display this node using
            // the inner nestedHierarchy/nestedItemId identity.
            hr = hierarchy.GetNestedHierarchy(itemid, ref hierGuid, out nestedHierarchyObj, out nestedItemId);
            if (VSConstants.S_OK == hr && IntPtr.Zero != nestedHierarchyObj)
            {
                IVsHierarchy nestedHierarchy = Marshal.GetObjectForIUnknown(nestedHierarchyObj) as IVsHierarchy;
                Marshal.Release(nestedHierarchyObj);    // we are responsible to release the refcount on the out IntPtr parameter
                if (nestedHierarchy != null)
                {
                    // Display name and type of the node in the Output Window
                    EnumHierarchyItems(nestedHierarchy, nestedItemId, recursionLevel, false, visibleNodesOnly, processNodeFunc);
                }
            }
            else
            {
                object pVar;

                // Display name and type of the node in the Output Window
                processNodeFunc(hierarchy, itemid, recursionLevel);

                recursionLevel++;

                //Get the first child node of the current hierarchy being walked
                // NOTE: to work around a bug with the Solution implementation of VSHPROPID_FirstChild,
                // we keep track of the recursion level. If we are asking for the first child under
                // the Solution, we use VSHPROPID_FirstVisibleChild instead of _FirstChild. 
                // In VS 2005 and earlier, the Solution improperly enumerates all nested projects
                // in the Solution (at any depth) as if they are immediate children of the Solution.
                // Its implementation _FirstVisibleChild is correct however, and given that there is
                // not a feature to hide a SolutionFolder or a Project, thus _FirstVisibleChild is 
                // expected to return the identical results as _FirstChild.
                hr = hierarchy.GetProperty(itemid,
                    ((visibleNodesOnly || (hierIsSolution && recursionLevel == 1) ?
                        (int)__VSHPROPID.VSHPROPID_FirstVisibleChild : (int)__VSHPROPID.VSHPROPID_FirstChild)),
                    out pVar);
                Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);
                if (VSConstants.S_OK == hr)
                {
                    //We are using Depth first search so at each level we recurse to check if the node has any children
                    // and then look for siblings.
                    uint childId = GetItemId(pVar);
                    while (childId != VSConstants.VSITEMID_NIL)
                    {
                        EnumHierarchyItems(hierarchy, childId, recursionLevel, false, visibleNodesOnly, processNodeFunc);
                        // NOTE: to work around a bug with the Solution implementation of VSHPROPID_NextSibling,
                        // we keep track of the recursion level. If we are asking for the next sibling under
                        // the Solution, we use VSHPROPID_NextVisibleSibling instead of _NextSibling. 
                        // In VS 2005 and earlier, the Solution improperly enumerates all nested projects
                        // in the Solution (at any depth) as if they are immediate children of the Solution.
                        // Its implementation   _NextVisibleSibling is correct however, and given that there is
                        // not a feature to hide a SolutionFolder or a Project, thus _NextVisibleSibling is 
                        // expected to return the identical results as _NextSibling.
                        hr = hierarchy.GetProperty(childId,
                            ((visibleNodesOnly || (hierIsSolution && recursionLevel == 1)) ?
                                (int)__VSHPROPID.VSHPROPID_NextVisibleSibling : (int)__VSHPROPID.VSHPROPID_NextSibling),
                            out pVar);
                        if (VSConstants.S_OK == hr)
                        {
                            childId = GetItemId(pVar);
                        }
                        else
                        {
                            Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);
                            break;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// This functions prints on the debug ouput and on the generic pane of the output window
        /// a text.
        /// </summary>
        /// <param name="text">text to send to Output Window.</param>
        private static void OutputCommandString(string text)
        {
            // Build the string to write on the debugger and output window.
            StringBuilder outputText = new StringBuilder(text);
            outputText.Append("\n");

            // Now print the string on the output window.
            // The first step is to get a reference to IVsOutputWindow.
            IVsOutputWindow outputWindow = Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow;
            // If we fail to get it we can exit now.
            if (null == outputWindow)
            {
                Trace.WriteLine("Failed to get a reference to IVsOutputWindow");
                return;
            }
            // Now get the window pane for the general output.
            Guid guidGeneral = Microsoft.VisualStudio.VSConstants.GUID_OutWindowGeneralPane;
            IVsOutputWindowPane windowPane;
            if (Microsoft.VisualStudio.ErrorHandler.Failed(outputWindow.GetPane(ref guidGeneral, out windowPane)))
            {
                Trace.WriteLine("Failed to get a reference to the Output Window General pane");
                return;
            }
            if (Microsoft.VisualStudio.ErrorHandler.Failed(windowPane.OutputString(outputText.ToString())))
            {
                Trace.WriteLine("Failed to write on the output window");
            }
        }

        /// <summary>
        /// Gets the item id.
        /// </summary>
        /// <param name="pvar">VARIANT holding an itemid.</param>
        /// <returns>Item Id of the concerned node</returns>
        private uint GetItemId(object pvar)
        {
            if (pvar == null) return VSConstants.VSITEMID_NIL;
            if (pvar is int) return (uint)(int)pvar;
            if (pvar is uint) return (uint)pvar;
            if (pvar is short) return (uint)(short)pvar;
            if (pvar is ushort) return (uint)(ushort)pvar;
            if (pvar is long) return (uint)(long)pvar;
            return VSConstants.VSITEMID_NIL;
        }


        private List<string> GetAllGeneratedFiles(string dirPath)
        {
            List<string> generatedFileList = new List<string>();

            try
            {
                if (!Directory.Exists(dirPath))
                {
                    //throw new Exception("Temp folder does not exists...");
                    return null;

                }
                else
                {
                    string[] allFilesArr = Directory.GetFiles(dirPath);
                    foreach (string item in allFilesArr)
                    {
                        generatedFileList.Add(item);
                    }

                    return generatedFileList;
                }


            }
            catch (Exception ex)
            {

                throw ex;
                //MessageBox.Show("Temp folder does not exists..." + ex.Message);
            }
        }

        private List<string> GetRulXFileForUpdate(string dirPath)
        {
            List<string> generatedFileList = new List<string>();

            try
            {
                if (!Directory.Exists(dirPath))
                {
                    //throw new Exception("Temp folder does not exists...");
                    return null;

                }
                else
                {
                    string[] allFilesArr = Directory.GetFiles(dirPath);
                    foreach (string item in allFilesArr)
                    {
                        generatedFileList.Add(item);
                    }

                    return generatedFileList;
                }


            }
            catch (Exception ex)
            {

                throw ex;
                //MessageBox.Show("Temp folder does not exists..." + ex.Message);
            }
        }

        private void HandleEvent()
        {
            try
            {
                BizRuleGenerater frmBizRuleSet = new BizRuleGenerater();
                frmBizRuleSet.ActiveSolutionFullName = SolutionFullName;
                
                //Checking the rulXFile and class name already exists in the currently selected project hierarchy

                //frmBizRuleSet.ShowDialog();
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private List<string> GetExistingRulXFileList()
        {
            try
            {
                List<string> existingRulXFileList = new List<string>();
                //EnvDTE.Project project = GetSelectedProjectHierarchyInstance();
                EnvDTE.Project project = VSEnvUtility.GetSelectedProjectHierarchyInstance();

                //UIHierarchy uih = (UIHierarchy)_applicationObject.Windows.Item(Constants.vsWindowKindSolutionExplorer).Object;
                //Array selectedItems = (Array)uih.SelectedItems;

                

                int indexOfDot = 0;
                indexOfDot = project.FullName.IndexOf('.');
                SelectedProjectType = project.FullName.Substring(indexOfDot);
                existingRulXFileList.Clear();
                foreach (ProjectItem item in project.ProjectItems)
                {
                    if (item.Name.ToUpper().Equals("BIZRULEGEN"))
                    {
                        ProjectItem itemRuleSetRootFolder = project.ProjectItems.Item("BIZRULEGEN");
                        foreach (ProjectItem rulXItem in itemRuleSetRootFolder.ProjectItems)
                        {
                            if (rulXItem.Name.EndsWith(".rulx"))
                            {
                                existingRulXFileList.Add(rulXItem.Name.Trim());
                            }

                            //ProjectItem rulXClassItem = rulXItem.ProjectItems.Item(rulXItem);
                            foreach (ProjectItem rulXClassItem in rulXItem.ProjectItems)
                            {
                                if (rulXClassItem.Name.EndsWith(".cs")
                                    || rulXClassItem.Name.EndsWith(".vb")
                                    || rulXClassItem.Name.EndsWith(".js"))
                                {
                                    existingRulXFileList.Add(rulXClassItem.Name.Trim());
                                }
                            }
                        }
                    }
                }


                return existingRulXFileList;
            }
            catch (Exception ex)
            {
                
                throw ex;
            }
        }

        public void AddItem(string classFileName, string ruleFileName)
        {
            try
            {
                int countRuleSetFolder = 1;
                StringBuilder str = new StringBuilder();
                bool isRootRuleSetDirFound = false;
                bool isXsdFileFound = false;

                EnvDTE.Project project = GetSelectedProjectHierarchyInstance();

                foreach (ProjectItem item in project.ProjectItems)
                {
                    if (item.Name.ToUpper().Equals("BIZRULEGEN"))
                    {
                        countRuleSetFolder++;
                        isRootRuleSetDirFound = true;
                        break;
                    }
                    str.Append(item.Name);
                    str.Append("||");
                }

                if (!isRootRuleSetDirFound)
                {
                    project.ProjectItems.AddFolder("BizRuleGen");
                    project.Save();

                    foreach (ProjectItem item in project.ProjectItems)
                    {
                        if (item.Name.ToUpper().Equals("BIZRULEGEN"))
                        {
                            ProjectItem itemRuleSetRootFolder = project.ProjectItems.Item("BIZRULEGEN");

                            itemRuleSetRootFolder.ProjectItems.AddFromFileCopy(ruleFileName);
                            
                            //Save the Project Hierarchy
                            project.Save();
                            break;
                        }


                    }
                    int lastIndex = ruleFileName.LastIndexOf('\\');
                    string finalRuleFileName = ruleFileName.Substring(lastIndex + 1);

                    ProjectItem itemRuleSetFolder = project.ProjectItems.Item("BIZRULEGEN");

                    ProjectItem itemRulexFile = itemRuleSetFolder.ProjectItems.Item(finalRuleFileName);
                    //Assigining custom tool 
                    itemRulexFile.Properties.Item("CustomTool").Value = "RulXObjectGenerator";

                    //itemRulexFile.ProjectItems.AddFromFileCopy(classFileName);
                    project.Save();

                    VSLangProj.VSProject vsCurrentProject = (VSLangProj.VSProject)project.Object;
                    vsCurrentProject.References.Add(RetrieveAssemblyDirectory() + @"\RulXFrameworkLib.dll");
                }
                else
                {
                    ProjectItem itemRuleSetRootFolder = project.ProjectItems.Item("BIZRULEGEN");

                    itemRuleSetRootFolder.ProjectItems.AddFromFileCopy(ruleFileName);
                    
                    //Save the Project Hierarchy
                    project.Save();


                    int lastIndex = ruleFileName.LastIndexOf('\\');
                    string finalRuleFileName = ruleFileName.Substring(lastIndex + 1);

                    ProjectItem itemRulexFile = itemRuleSetRootFolder.ProjectItems.Item(finalRuleFileName);
                    //Assigining custom tool 
                    itemRulexFile.Properties.Item("CustomTool").Value = "RulXObjectGenerator";
                    //itemRulexFile.ProjectItems.AddFromFileCopy(classFileName);
                    project.Save();
                }

                //////////////////////////////
                const string userRoot = @"HKEY_LOCAL_MACHINE";
                const string subkey = @"Software\Microsoft\VisualStudio\10.0\Packages\FrameworkLib\Path";
                const string keyName = userRoot + "\\" + subkey;

                //////////////////////////////

                //VSLangProj.VSProject vsCurrentProject = (VSLangProj.VSProject)project.Object;
                string strSystemRoot = Environment.GetEnvironmentVariable("SystemRoot");
                //vsCurrentProject.References.Add(strSystemRoot + @"\Microsoft.NET\assembly\GAC_MSIL\RulXFrameworkLib\v4.0_1.0.0.0__c491372f62ac8680\RulXFrameworkLib.dll");
                //References refs = vsCurrentProject.References.Find("");
                //vsCurrentProject.References.Add(RetrieveAssemblyDirectory() + @"\RulXFrameworkLib.dll");
                
                //Deleting he temp folder
                DeleteTempOutputDir();
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }

        public void UpdateItem(string ruleFileName)
        {
            try
            {
                int countRuleSetFolder = 1;
                StringBuilder str = new StringBuilder();
                bool isRootRuleSetDirFound = false;
                

                EnvDTE.Project project = GetSelectedProjectHierarchyInstance();

                ProjectItem itemRuleSetRootFolder = project.ProjectItems.Item("BIZRULEGEN");


                //Save the Project Hierarchy
                project.Save();


                int lastIndex = ruleFileName.LastIndexOf('\\');
                string finalRuleFileName = ruleFileName.Substring(lastIndex + 1);

                ProjectItem itemRulexFile = itemRuleSetRootFolder.ProjectItems.Item(finalRuleFileName);
                //Assigining custom tool
                itemRulexFile.Properties.Item("CustomTool").Value = "";
                //itemRulexFile.ProjectItems.AddFromFileCopy(classFileName);
                project.Save();
                itemRulexFile.Properties.Item("CustomTool").Value = "RulXObjectGenerator";
                //itemRulexFile.ProjectItems.AddFromFileCopy(classFileName);
                project.Save();
              
                //////////////////////////////
                const string userRoot = @"HKEY_LOCAL_MACHINE";
                const string subkey = @"Software\Microsoft\VisualStudio\10.0\Packages\FrameworkLib\Path";
                const string keyName = userRoot + "\\" + subkey;

                //////////////////////////////

                string strSystemRoot = Environment.GetEnvironmentVariable("SystemRoot");
                
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }

        private static string RetrieveAssemblyDirectory()
        {
            string codeBase = Assembly.GetExecutingAssembly().CodeBase;
            var uri = new UriBuilder(codeBase);
            string path = Uri.UnescapeDataString(uri.Path);
            return Path.GetDirectoryName(path);
        }

        private EnvDTE.Project GetSelectedProjectHierarchyInstance()
        {
            IVsHierarchy hierarchy = null;
            IntPtr hierarchyPtr = IntPtr.Zero;
            IntPtr selectionContainer = IntPtr.Zero;
            uint itemid;
            string currentDocument;


            // Retrieve shell interface in order to get current selection
            IVsMonitorSelection monitorSelection = Package.GetGlobalService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
            if (monitorSelection == null)
                throw new InvalidOperationException();

            try
            {
                // Get the current project hierarchy, project item, and selection container for the current selection
                // If the selection spans multiple hierachies, hierarchyPtr is Zero
                IVsMultiItemSelect multiItemSelect = null;
                ErrorHandler.ThrowOnFailure(
                    monitorSelection.GetCurrentSelection(
                        out hierarchyPtr, out itemid,
                        out multiItemSelect, out selectionContainer));

                // We only care if there is only one node selected in the tree
                if (!(itemid == VSConstants.VSITEMID_NIL ||
                    hierarchyPtr == IntPtr.Zero ||
                    multiItemSelect != null ||
                    itemid == VSConstants.VSITEMID_SELECTION))
                {
                    hierarchy = Marshal.GetObjectForIUnknown(hierarchyPtr)
                        as IVsHierarchy;
                }

                uint itemId;
                object objProj;
                int hr = hierarchy.GetCanonicalName(itemid, out currentDocument);
                hierarchy.ParseCanonicalName(currentDocument, out itemId);

                hierarchy.GetProperty((uint)VSConstants.VSITEMID_ROOT, (int)__VSHPROPID.VSHPROPID_ExtObject, out objProj);
                EnvDTE.Project dteProject = (EnvDTE.Project)objProj;



                return dteProject;
            }
            finally
            {
                if (hierarchyPtr != IntPtr.Zero)
                    Marshal.Release(hierarchyPtr);
                if (selectionContainer != IntPtr.Zero)
                    Marshal.Release(selectionContainer);
            }
        }

        private void EnumHierarchyItemsFlat(uint itemid, IVsHierarchy hierarchy, int recursionLevel, bool visibleNodesOnly, ProcessHierarchyNode processNodeFunc)
        {
            // Display name and type of the node in the Output Window
            processNodeFunc(hierarchy, itemid, recursionLevel);

            int hr;
            object pVar;

            recursionLevel++;

            //Get the first child node of the current hierarchy being walked
            hr = hierarchy.GetProperty(itemid,
                (visibleNodesOnly ? (int)__VSHPROPID.VSHPROPID_FirstVisibleChild : (int)__VSHPROPID.VSHPROPID_FirstChild),
                out pVar);
            Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);
            if (VSConstants.S_OK == hr)
            {
                //We are using Depth first search so at each level we recurse to check if the node has any children
                // and then look for siblings.
                uint childId = GetItemId(pVar);
                while (childId != VSConstants.VSITEMID_NIL)
                {
                    EnumHierarchyItemsFlat(childId, hierarchy, recursionLevel, visibleNodesOnly, processNodeFunc);
                    hr = hierarchy.GetProperty(childId,
                        (visibleNodesOnly ? (int)__VSHPROPID.VSHPROPID_NextVisibleSibling : (int)__VSHPROPID.VSHPROPID_NextSibling),
                        out pVar);
                    if (VSConstants.S_OK == hr)
                    {
                        childId = GetItemId(pVar);
                    }
                    else
                    {
                        Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);
                        break;
                    }
                }
            }
        }

        private void DeleteTempOutputDir()
        {
            try
            {
                if (Directory.Exists(tempOutputDir))
                {
                    // Delete the target to ensure it is not there.
                    Directory.Delete(tempOutputDir, true);
                    //MessageBox.Show("Temp folder deleted successfully...");

                }

            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message);
            }
        }

        private void ExecuteRuleXAction()
        {
            string classFile = string.Empty;
            string ruleFile = string.Empty;

            
            HandleEvent();
            //MessageBox.Show("Returning....");
            //Add all he generated files into VS IDE
                

            List<string> listAllFiles = new List<string>();
            listAllFiles = GetAllGeneratedFiles(tempOutputDir);
            foreach (string item in listAllFiles)
            {
                if (item.EndsWith(".cs")
                    || item.EndsWith(".vb")
                    || item.EndsWith(".js"))
                {
                    classFile = item;

                }
                else if (item.EndsWith(".rulx"))
                {
                    ruleFile = item;
                }
            }

            AddItem(classFile, ruleFile);
            
        }

        private void ExecuteRuleXActionForUpdate(string sRulXFileName)
        {
            
            HandleEvent();
            //MessageBox.Show("Returning....");
            //Add all he generated files into VS IDE

            UpdateItem(sRulXFileName);

        }

        private DTE2 _applicationObject;
        private AddIn _addInInstance;

        #endregion

    }
}
